﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace DOTNET101_Threading
{
    class Program
    {

        static void Main(string[] args)
        {
            ThreadingExample.Test();

            System.Object obj = new System.Object();
            System.Threading.Monitor.Enter(obj);
            try
            {
                // DoSomething();
            }
            finally
            {
                System.Threading.Monitor.Exit(obj);
            }
        }

        object lockA = new object();
        object lockB = new object();

        // Thread 1
        void t1()
        {
            lock (lockA)
            {
                lock (lockB)
                {
                    /* ... */
                }
            }
        }

        // Thread 2
        void t2()
        {
            lock (lockB)
            {
                lock (lockA)
                {
                    /* ... */
                }
            }
        }

        class InsufficientFundsException : Exception
        {
            public override string ToString()
            {
                return base.ToString();
            }
        }

        public class Account
        {
            public decimal Balance { get; set; }
        }

        void Transfer(Account a, Account b, decimal amount)
        {
            lock (a)
            {
                lock (b)
                {
                    if (a.Balance < amount)
                        throw new InsufficientFundsException();
                    a.Balance -= amount;
                    b.Balance += amount;
                }
            }
        }

        public class LeveledLock
        {
            // Declare the constructore
            public LeveledLock(int level)
            {
                Level = level;       
            }

            // Delcar a property
            public int Level { get; set; }
        }

        LeveledLock lockAx = new LeveledLock(10);
        LeveledLock lockBx = new LeveledLock(5);

        public class TestThreading
        {
            private System.Object lockThis = new System.Object();

            public void Function()
            {

                lock (lockThis)
                {
                    // Access thread-sensitive resources.
                }
            }

        }
    }

    class ThreadingExample
    {
        static AutoResetEvent autoEvent;

        static void DoWork()
        {
            Console.WriteLine("   worker thread started, now waiting on event...");
            autoEvent.WaitOne();
            Console.WriteLine("   worker thread reactivated, now exiting...");
        }

        public static void Test()
        {
            autoEvent = new AutoResetEvent(false);

            Console.WriteLine("main thread starting worker thread...");
            Thread t = new Thread(DoWork);
            t.Start();

            Console.WriteLine("main thread sleeping for 1 second...");
            Thread.Sleep(1000);

            Console.WriteLine("main thread signaling worker thread...");
            autoEvent.Set();
        }
    }

using System;
using System.Threading;

    public class Worker
    {
        // This method will be called when the thread is started.
        public void DoWork()
        {
            while (!_shouldStop)
            {
                Console.WriteLine("worker thread: working...");
            }
            Console.WriteLine("worker thread: terminating gracefully.");
        }
        public void RequestStop()
        {
            _shouldStop = true;
        }
        // Volatile is used as hint to the compiler that this data
        // member will be accessed by multiple threads.
        private volatile bool _shouldStop;
    }

    public class WorkerThreadExample
    {
        public static void Test()
        {
            // Create the thread object. This does not start the thread.
            Worker workerObject = new Worker();
            Thread workerThread = new Thread(workerObject.DoWork);
            
            // Start the worker thread.
            workerThread.Start();
            Console.WriteLine("main thread: Starting worker thread...");
            
            // Loop until worker thread activates.
            while (!workerThread.IsAlive);

            // Put the main thread to sleep for 1 millisecond to
            // allow the worker thread to do some work:
            Thread.Sleep(1);

            // Request that the worker thread stop itself:
            workerObject.RequestStop();

            // Use the Join method to block the current thread 
            // until the object's thread terminates.
            workerThread.Join();
            Console.WriteLine("main thread: Worker thread has terminated.");
        }
    }
}
